🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / core / data / src / commonMain / kotlin / org / meshtastic / core / data / manager / NodeManagerImpl.kt
Displaying Raw • Download
core/data/src/commonMain/kotlin/org/meshtastic/core/data/manager/NodeManagerImpl.kt 4e15ef1c7f68f8c683fe8b7ff741a5167e154d2e (4e15ef1c) Text, 14.77 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.data.manager
Tff7b72import T7ee787co.touchlab.kermit.Logger
Tff7b72import T7ee787kotlinx.atomicfu.atomic
Tff7b72import T7ee787kotlinx.atomicfu.update
Tff7b72import T7ee787kotlinx.collections.immutable.PersistentMap
Tff7b72import T7ee787kotlinx.collections.immutable.persistentMapOf
Tff7b72import T7ee787kotlinx.coroutines.CoroutineScope
Tff7b72import T7ee787kotlinx.coroutines.flow.MutableStateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.first
Tff7b72import T7ee787okio.ByteString
Tff7b72import T7ee787org.koin.core.annotation.Named
Tff7b72import T7ee787org.koin.core.annotation.Single
Tff7b72import T7ee787org.meshtastic.core.common.util.clampTimestampToNow
Tff7b72import T7ee787org.meshtastic.core.common.util.handledLaunch
Tff7b72import T7ee787org.meshtastic.core.model.MyNodeInfo
Tff7b72import T7ee787org.meshtastic.core.model.Node
Tff7b72import T7ee787org.meshtastic.core.model.NodeAddress
Tff7b72import T7ee787org.meshtastic.core.model.util.NodeIdLookup
Tff7b72import T7ee787org.meshtastic.core.repository.NodeManager
Tff7b72import T7ee787org.meshtastic.core.repository.NodeRepository
Tff7b72import T7ee787org.meshtastic.core.repository.Notification
Tff7b72import T7ee787org.meshtastic.core.repository.NotificationManager
Tff7b72import T7ee787org.meshtastic.core.resources.Res
Tff7b72import T7ee787org.meshtastic.core.resources.getStringSuspend
Tff7b72import T7ee787org.meshtastic.core.resources.new_node_seen
Tff7b72import T7ee787org.meshtastic.proto.DeviceMetadata
Tff7b72import T7ee787org.meshtastic.proto.FirmwareEdition
Tff7b72import T7ee787org.meshtastic.proto.HardwareModel
Tff7b72import T7ee787org.meshtastic.proto.Paxcount
Tff7b72import T7ee787org.meshtastic.proto.StatusMessage
Tff7b72import T7ee787org.meshtastic.proto.Telemetry
Tff7b72import T7ee787org.meshtastic.proto.User
Tff7b72import T7ee787org.meshtastic.proto.NodeInfo Tff7b72as Te6edf3ProtoNodeInfo
Tff7b72import T7ee787org.meshtastic.proto.Position Tff7b72as Te6edf3ProtoPosition
T8b949e/** Implementation of [NodeManager] that maintains an in-memory database of the mesh. */
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffLongParameterListTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffTooManyFunctionsTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffCyclomaticComplexMethodTa5d6ff"Tb4b4b4)
Tf0883e@SingleTb4b4b4(Te6edf3binds Tff7b72= Tff7b72[Te6edf3NodeManagerTff7b72::Te6edf3classTb4b4b4, Te6edf3NodeIdLookupTff7b72::Te6edf3classTff7b72]Tb4b4b4)
Tff7b72class T56d364NodeManagerImplTb4b4b4(
Tff7b72private Tff7b72val Te6edf3nodeRepositoryTb4b4b4: Te6edf3NodeRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3notificationManagerTb4b4b4: Te6edf3NotificationManagerTb4b4b4,
Tf0883e@NamedTb4b4b4(Ta5d6ff"Ta5d6ffServiceScopeTa5d6ff"Tb4b4b4) Tff7b72private Tff7b72val Te6edf3scopeTb4b4b4: Te6edf3CoroutineScopeTb4b4b4,
Tb4b4b4) Tb4b4b4: Te6edf3NodeManager Tb4b4b4{
T8b949e// Two indices over the same node set: byNum is the canonical store (mesh-level identifier), byId is a secondary
T8b949e// O(1) lookup for the user-facing hex string. Both are held in a single atomic ref so updates are observed
T8b949e// consistently — concurrent readers never see an entry present in one index but not the other.
Tff7b72private Tff7b72data Tff7b72class T56d364NodeIndexTb4b4b4(
Tff7b72val Te6edf3byNumTb4b4b4: Te6edf3PersistentMapTff7b72<Tffa657IntTb4b4b4, Te6edf3NodeTff7b72> Tff7b72= Te6edf3persistentMapOfTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3byIdTb4b4b4: Te6edf3PersistentMapTff7b72<Tffa657StringTb4b4b4, Te6edf3NodeTff7b72> Tff7b72= Te6edf3persistentMapOfTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72fun Td2a8ffputTb4b4b4(Te6edf3numTb4b4b4: Tffa657IntTb4b4b4, Te6edf3nodeTb4b4b4: Te6edf3NodeTb4b4b4)Tb4b4b4: Te6edf3NodeIndex Tb4b4b4{
Tff7b72val Te6edf3previous Tff7b72= Te6edf3byNumTff7b72[Te6edf3numTff7b72]
Tff7b72var Te6edf3nextById Tff7b72= Te6edf3byId
T8b949e// If the user.id changed (e.g. firmware reassigned the hex id) drop the stale id entry.
Tff7b72if Tb4b4b4(Te6edf3previous Tff7b72!Tff7b72= Tff7b72null Tff7b72&Tff7b72& Te6edf3previousTb4b4b4.Te6edf3userTb4b4b4.Te6edf3idTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3previousTb4b4b4.Te6edf3userTb4b4b4.Te6edf3id Tff7b72!Tff7b72= Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3idTb4b4b4) Tb4b4b4{
Te6edf3nextById Tff7b72= Te6edf3nextByIdTb4b4b4.Te6edf3removeTb4b4b4(Te6edf3previousTb4b4b4.Te6edf3userTb4b4b4.Te6edf3idTb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3idTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3nextById Tff7b72= Te6edf3nextByIdTb4b4b4.Te6edf3putTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3idTb4b4b4, Te6edf3nodeTb4b4b4)
Tb4b4b4}
Tff7b72return Te6edf3NodeIndexTb4b4b4(Te6edf3byNum Tff7b72= Te6edf3byNumTb4b4b4.Te6edf3putTb4b4b4(Te6edf3numTb4b4b4, Te6edf3nodeTb4b4b4)Tb4b4b4, Te6edf3byId Tff7b72= Te6edf3nextByIdTb4b4b4)
Tb4b4b4}
Tff7b72fun Td2a8ffremoveTb4b4b4(Te6edf3numTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Te6edf3NodeIndex Tb4b4b4{
Tff7b72val Te6edf3previous Tff7b72= Te6edf3byNumTff7b72[Te6edf3numTff7b72] Tff7b72?: Tff7b72return Tff7b72this
Tff7b72return Te6edf3NodeIndexTb4b4b4(
Te6edf3byNum Tff7b72= Te6edf3byNumTb4b4b4.Te6edf3removeTb4b4b4(Te6edf3numTb4b4b4)Tb4b4b4,
Te6edf3byId Tff7b72= Tff7b72if Tb4b4b4(Te6edf3previousTb4b4b4.Te6edf3userTb4b4b4.Te6edf3idTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3byIdTb4b4b4.Te6edf3removeTb4b4b4(Te6edf3previousTb4b4b4.Te6edf3userTb4b4b4.Te6edf3idTb4b4b4) Tff7b72else Te6edf3byIdTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tff7b72companion Tff7b72object Tb4b4b4{
Tff7b72fun Td2a8fffromByNumTb4b4b4(Te6edf3nodesTb4b4b4: Te6edf3MapTff7b72<Tffa657IntTb4b4b4, Te6edf3NodeTff7b72>Tb4b4b4)Tb4b4b4: Te6edf3NodeIndex Tb4b4b4{
Tff7b72var Te6edf3byNum Tff7b72= Te6edf3persistentMapOfTff7b72<Tffa657IntTb4b4b4, Te6edf3NodeTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72var Te6edf3byId Tff7b72= Te6edf3persistentMapOfTff7b72<Tffa657StringTb4b4b4, Te6edf3NodeTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72for Tb4b4b4(Tb4b4b4(Te6edf3numTb4b4b4, Te6edf3nodeTb4b4b4) Tff7b72in Te6edf3nodesTb4b4b4) Tb4b4b4{
Te6edf3byNum Tff7b72= Te6edf3byNumTb4b4b4.Te6edf3putTb4b4b4(Te6edf3numTb4b4b4, Te6edf3nodeTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3idTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Te6edf3byId Tff7b72= Te6edf3byIdTb4b4b4.Te6edf3putTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3idTb4b4b4, Te6edf3nodeTb4b4b4)
Tb4b4b4}
Tff7b72return Te6edf3NodeIndexTb4b4b4(Te6edf3byNumTb4b4b4, Te6edf3byIdTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72val Te6edf3nodeIndex Tff7b72= Te6edf3atomicTb4b4b4(Te6edf3NodeIndexTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72override Tff7b72val Te6edf3nodeDBbyNodeNumTb4b4b4: Te6edf3MapTff7b72<Tffa657IntTb4b4b4, Te6edf3NodeTff7b72>
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3nodeIndexTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3byNum
Tff7b72override Tff7b72fun Td2a8ffgetNodeByIdTb4b4b4(Te6edf3idTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Te6edf3Node? Tff7b72= Te6edf3nodeIndexTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3byIdTff7b72[Te6edf3idTff7b72]
Tff7b72override Tff7b72val Te6edf3isNodeDbReady Tff7b72= Te6edf3MutableStateFlowTb4b4b4(Tff7b72falseTb4b4b4)
Tff7b72override Tff7b72val Te6edf3allowNodeDbWrites Tff7b72= Te6edf3MutableStateFlowTb4b4b4(Tff7b72falseTb4b4b4)
Tff7b72override Tff7b72fun Td2a8ffsetNodeDbReadyTb4b4b4(Te6edf3readyTb4b4b4: Tffa657BooleanTb4b4b4) Tb4b4b4{
Te6edf3isNodeDbReadyTb4b4b4.Te6edf3value Tff7b72= Te6edf3ready
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffsetAllowNodeDbWritesTb4b4b4(Te6edf3allowedTb4b4b4: Tffa657BooleanTb4b4b4) Tb4b4b4{
Te6edf3allowNodeDbWritesTb4b4b4.Te6edf3value Tff7b72= Te6edf3allowed
Tb4b4b4}
Tff7b72override Tff7b72val Te6edf3myNodeNum Tff7b72= Te6edf3MutableStateFlowTff7b72<Tffa657Int?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4)
Tff7b72override Tff7b72fun Td2a8ffsetMyNodeNumTb4b4b4(Te6edf3numTb4b4b4: Tffa657Int?Tb4b4b4) Tb4b4b4{
Te6edf3myNodeNumTb4b4b4.Te6edf3value Tff7b72= Te6edf3num
Tb4b4b4}
Tff7b72override Tff7b72val Te6edf3firmwareEdition Tff7b72= Te6edf3MutableStateFlowTff7b72<Te6edf3FirmwareEdition?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4)
Tff7b72override Tff7b72fun Td2a8ffsetFirmwareEditionTb4b4b4(Te6edf3editionTb4b4b4: Te6edf3FirmwareEdition?Tb4b4b4) Tb4b4b4{
Te6edf3firmwareEditionTb4b4b4.Te6edf3value Tff7b72= Te6edf3edition
Tb4b4b4}
Tff7b72companion Tff7b72object Tb4b4b4{
Tff7b72private Tff7b72const Tff7b72val Te6edf3TIME_MS_TO_S Tff7b72= T79c0ff1T79c0ff0T79c0ff0T79c0ff0L
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffloadCachedNodeDBTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{
Tff7b72val Te6edf3nodes Tff7b72= Te6edf3nodeRepositoryTb4b4b4.Te6edf3nodeDBbyNumTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3nodeIndexTb4b4b4.Te6edf3value Tff7b72= Te6edf3NodeIndexTb4b4b4.Te6edf3fromByNumTb4b4b4(Te6edf3nodesTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3myNodeNumTb4b4b4.Te6edf3value Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3myNodeNumTb4b4b4.Te6edf3value Tff7b72= Te6edf3nodeRepositoryTb4b4b4.Te6edf3myNodeInfoTb4b4b4.Te6edf3valueTff7b72?.Te6edf3myNodeNum
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffclearTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3nodeIndexTb4b4b4.Te6edf3value Tff7b72= Te6edf3NodeIndexTb4b4b4(Tb4b4b4)
Te6edf3isNodeDbReadyTb4b4b4.Te6edf3value Tff7b72= Tff7b72false
Te6edf3allowNodeDbWritesTb4b4b4.Te6edf3value Tff7b72= Tff7b72false
Te6edf3myNodeNumTb4b4b4.Te6edf3value Tff7b72= Tff7b72null
Te6edf3firmwareEditionTb4b4b4.Te6edf3value Tff7b72= Tff7b72null
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffgetMyNodeInfoTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3MyNodeInfo? Tb4b4b4{
Tff7b72val Te6edf3mi Tff7b72= Te6edf3nodeRepositoryTb4b4b4.Te6edf3myNodeInfoTb4b4b4.Te6edf3value Tff7b72?: Tff7b72return Tff7b72null
Tff7b72val Te6edf3myNode Tff7b72= Te6edf3nodeIndexTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3byNumTff7b72[Te6edf3miTb4b4b4.Te6edf3myNodeNumTff7b72]
Tff7b72return Te6edf3MyNodeInfoTb4b4b4(
Te6edf3myNodeNum Tff7b72= Te6edf3miTb4b4b4.Te6edf3myNodeNumTb4b4b4,
Te6edf3hasGPS Tff7b72= Tb4b4b4(Te6edf3myNodeTff7b72?.Te6edf3positionTff7b72?.Te6edf3latitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72!Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3model Tff7b72= Te6edf3miTb4b4b4.Te6edf3model Tff7b72?: Te6edf3myNodeTff7b72?.Te6edf3userTff7b72?.Te6edf3hw_modelTff7b72?.Te6edf3nameTb4b4b4,
Te6edf3firmwareVersion Tff7b72= Te6edf3miTb4b4b4.Te6edf3firmwareVersionTb4b4b4,
Te6edf3couldUpdate Tff7b72= Te6edf3miTb4b4b4.Te6edf3couldUpdateTb4b4b4,
Te6edf3shouldUpdate Tff7b72= Te6edf3miTb4b4b4.Te6edf3shouldUpdateTb4b4b4,
Te6edf3currentPacketId Tff7b72= Te6edf3miTb4b4b4.Te6edf3currentPacketIdTb4b4b4,
Te6edf3messageTimeoutMsec Tff7b72= Te6edf3miTb4b4b4.Te6edf3messageTimeoutMsecTb4b4b4,
Te6edf3minAppVersion Tff7b72= Te6edf3miTb4b4b4.Te6edf3minAppVersionTb4b4b4,
Te6edf3maxChannels Tff7b72= Te6edf3miTb4b4b4.Te6edf3maxChannelsTb4b4b4,
Te6edf3hasWifi Tff7b72= Te6edf3miTb4b4b4.Te6edf3hasWifiTb4b4b4,
Te6edf3channelUtilization Tff7b72= T79c0ff0fTb4b4b4,
Te6edf3airUtilTx Tff7b72= T79c0ff0fTb4b4b4,
Te6edf3deviceId Tff7b72= Te6edf3miTb4b4b4.Te6edf3deviceId Tff7b72?: Te6edf3myNodeTff7b72?.Te6edf3userTff7b72?.Te6edf3idTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffgetMyIdTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657String Tb4b4b4{
Tff7b72val Te6edf3num Tff7b72= Te6edf3myNodeNumTb4b4b4.Te6edf3value Tff7b72?: Te6edf3nodeRepositoryTb4b4b4.Te6edf3myNodeInfoTb4b4b4.Te6edf3valueTff7b72?.Te6edf3myNodeNum Tff7b72?: Tff7b72return Ta5d6ff"Ta5d6ff"
Tff7b72return Te6edf3nodeIndexTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3byNumTff7b72[Te6edf3numTff7b72]Tff7b72?.Te6edf3userTff7b72?.Te6edf3id Tff7b72?: Ta5d6ff"Ta5d6ff"
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffremoveByNodenumTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3nodeIndexTb4b4b4.Te6edf3update Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3removeTb4b4b4(Te6edf3nodeNumTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72internal Tff7b72fun Td2a8ffgetOrCreateNodeTb4b4b4(Te6edf3nTb4b4b4: Tffa657IntTb4b4b4, Te6edf3channelTb4b4b4: Tffa657Int Tff7b72= T79c0ff0Tb4b4b4)Tb4b4b4: Te6edf3Node Tff7b72= Te6edf3nodeIndexTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3byNumTff7b72[Te6edf3nTff7b72]
Tff7b72?: Te6edf3run Tb4b4b4{
Tff7b72val Te6edf3userId Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3numToDefaultIdTb4b4b4(Te6edf3nTb4b4b4)
Tff7b72val Te6edf3defaultUser Tff7b72=
Te6edf3UserTb4b4b4(
Te6edf3id Tff7b72= Te6edf3userIdTb4b4b4,
Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffMeshtastic Tffd700${Te6edf3userIdTb4b4b4.Te6edf3takeLastTb4b4b4(Te6edf3n Tff7b72= T79c0ff4Tb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4,
Te6edf3short_name Tff7b72= Te6edf3userIdTb4b4b4.Te6edf3takeLastTb4b4b4(Te6edf3n Tff7b72= T79c0ff4Tb4b4b4)Tb4b4b4,
Te6edf3hw_model Tff7b72= Te6edf3HardwareModelTb4b4b4.Te6edf3UNSETTb4b4b4,
Tb4b4b4)
Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= Te6edf3nTb4b4b4, Te6edf3user Tff7b72= Te6edf3defaultUserTb4b4b4, Te6edf3channel Tff7b72= Te6edf3channelTb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffupdateNodeTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3channelTb4b4b4: Tffa657IntTb4b4b4, Te6edf3transformTb4b4b4: Tb4b4b4(Te6edf3NodeTb4b4b4) Tff7b72-Tff7b72> Te6edf3NodeTb4b4b4) Tb4b4b4{
T8b949e// Perform read + transform inside update{} to ensure atomicity.
T8b949e// Without this, concurrent calls for the same nodeNum could read the same snapshot
T8b949e// and the last writer would silently overwrite the other's changes.
Tff7b72var Te6edf3nextTb4b4b4: Te6edf3Node? Tff7b72= Tff7b72null
Te6edf3nodeIndexTb4b4b4.Te6edf3update Tb4b4b4{ Te6edf3index Tff7b72-Tff7b72>
Tff7b72val Te6edf3current Tff7b72= Te6edf3indexTb4b4b4.Te6edf3byNumTff7b72[Te6edf3nodeNumTff7b72] Tff7b72?: Te6edf3getOrCreateNodeTb4b4b4(Te6edf3nodeNumTb4b4b4, Te6edf3channelTb4b4b4)
Tff7b72val Te6edf3transformed Tff7b72= Te6edf3transformTb4b4b4(Te6edf3currentTb4b4b4)
Te6edf3next Tff7b72= Te6edf3transformed
Te6edf3indexTb4b4b4.Te6edf3putTb4b4b4(Te6edf3nodeNumTb4b4b4, Te6edf3transformedTb4b4b4)
Tb4b4b4}
Tff7b72val Te6edf3result Tff7b72= Te6edf3next Tff7b72?: Tff7b72return
Tff7b72if Tb4b4b4(Te6edf3resultTb4b4b4.Te6edf3userTb4b4b4.Te6edf3idTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3isNodeDbReadyTb4b4b4.Te6edf3valueTb4b4b4) Tb4b4b4{
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{ Te6edf3nodeRepositoryTb4b4b4.Te6edf3upsertTb4b4b4(Te6edf3resultTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffhandleReceivedUserTb4b4b4(Te6edf3fromNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3pTb4b4b4: Te6edf3UserTb4b4b4, Te6edf3channelTb4b4b4: Tffa657IntTb4b4b4, Te6edf3manuallyVerifiedTb4b4b4: Tffa657BooleanTb4b4b4) Tb4b4b4{
Te6edf3updateNodeTb4b4b4(Te6edf3fromNumTb4b4b4) Tb4b4b4{ Te6edf3node Tff7b72-Tff7b72>
Tff7b72val Te6edf3newNode Tff7b72= Tb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3isUnknownUser Tff7b72&Tff7b72& Te6edf3pTb4b4b4.Te6edf3hw_model Tff7b72!Tff7b72= Te6edf3HardwareModelTb4b4b4.Te6edf3UNSETTb4b4b4)
Tff7b72val Te6edf3shouldPreserve Tff7b72= Te6edf3shouldPreserveExistingUserTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4, Te6edf3pTb4b4b4)
Tff7b72val Te6edf3next Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3shouldPreserveTb4b4b4) Tb4b4b4{
Te6edf3nodeTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3channel Tff7b72= Te6edf3channelTb4b4b4, Te6edf3manuallyVerified Tff7b72= Te6edf3manuallyVerifiedTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72val Te6edf3keyMatch Tff7b72= Tff7b72!Te6edf3nodeTb4b4b4.Te6edf3hasPKC Tff7b72|Tff7b72| Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4.Te6edf3public_key Tff7b72=Tff7b72= Te6edf3pTb4b4b4.Te6edf3public_key
Tff7b72val Te6edf3newUser Tff7b72= Tff7b72if Tb4b4b4(Te6edf3keyMatchTb4b4b4) Te6edf3p Tff7b72else Te6edf3pTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3public_key Tff7b72= Te6edf3ByteStringTb4b4b4.Te6edf3EMPTYTb4b4b4)
Te6edf3nodeTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3user Tff7b72= Te6edf3newUserTb4b4b4,
Te6edf3publicKey Tff7b72= Te6edf3newUserTb4b4b4.Te6edf3public_keyTb4b4b4,
Te6edf3channel Tff7b72= Te6edf3channelTb4b4b4,
Te6edf3manuallyVerified Tff7b72= Te6edf3manuallyVerifiedTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3newNode Tff7b72&Tff7b72& Tff7b72!Te6edf3shouldPreserveTb4b4b4) Tb4b4b4{
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{
Te6edf3notificationManagerTb4b4b4.Te6edf3dispatchTb4b4b4(
Te6edf3NotificationTb4b4b4(
Te6edf3title Tff7b72= Te6edf3getStringSuspendTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3new_node_seenTb4b4b4, Te6edf3nextTb4b4b4.Te6edf3userTb4b4b4.Te6edf3short_nameTb4b4b4)Tb4b4b4,
Te6edf3message Tff7b72= Te6edf3nextTb4b4b4.Te6edf3userTb4b4b4.Te6edf3long_nameTb4b4b4,
Te6edf3category Tff7b72= Te6edf3NotificationTb4b4b4.Te6edf3CategoryTb4b4b4.Te6edf3NodeEventTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Te6edf3next
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffhandleReceivedPositionTb4b4b4(Te6edf3fromNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3myNodeNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3pTb4b4b4: Te6edf3ProtoPositionTb4b4b4, Te6edf3defaultTimeTb4b4b4: Tffa657LongTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3isZeroPos Tff7b72= Tb4b4b4(Te6edf3pTb4b4b4.Te6edf3latitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72=Tff7b72= T79c0ff0 Tff7b72&Tff7b72& Tb4b4b4(Te6edf3pTb4b4b4.Te6edf3longitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72=Tff7b72= T79c0ff0
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffComplexConditionTa5d6ff"Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3myNodeNum Tff7b72=Tff7b72= Te6edf3fromNum Tff7b72&Tff7b72& Te6edf3isZeroPos Tff7b72&Tff7b72& Te6edf3pTb4b4b4.Te6edf3sats_in_view Tff7b72=Tff7b72= T79c0ff0 Tff7b72&Tff7b72& Te6edf3pTb4b4b4.Te6edf3time Tff7b72=Tff7b72= T79c0ff0Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffIgnoring empty position update for the local nodeTa5d6ff" Tb4b4b4}
Tff7b72return
Tb4b4b4}
Te6edf3updateNodeTb4b4b4(Te6edf3fromNumTb4b4b4) Tb4b4b4{ Te6edf3node Tff7b72-Tff7b72>
Tff7b72val Te6edf3rawPosTime Tff7b72= Tff7b72if Tb4b4b4(Te6edf3pTb4b4b4.Te6edf3time Tff7b72!Tff7b72= T79c0ff0Tb4b4b4) Te6edf3pTb4b4b4.Te6edf3time Tff7b72else Tb4b4b4(Te6edf3defaultTime Tff7b72/ Te6edf3TIME_MS_TO_STb4b4b4)Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3posTime Tff7b72= Te6edf3clampTimestampToNowTb4b4b4(Te6edf3rawPosTimeTb4b4b4)
Tff7b72val Te6edf3newLastHeard Tff7b72= Te6edf3maxOfTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3lastHeardTb4b4b4, Te6edf3posTimeTb4b4b4)
Tff7b72val Te6edf3newPos Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3isZeroPosTb4b4b4) Tb4b4b4{
Te6edf3pTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3time Tff7b72= Te6edf3posTimeTb4b4b4,
Te6edf3latitude_i Tff7b72= Te6edf3nodeTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3latitude_iTb4b4b4,
Te6edf3longitude_i Tff7b72= Te6edf3nodeTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3longitude_iTb4b4b4,
Te6edf3altitude Tff7b72= Te6edf3pTb4b4b4.Te6edf3altitude Tff7b72?: Te6edf3nodeTb4b4b4.Te6edf3positionTb4b4b4.Te6edf3altitudeTb4b4b4,
Te6edf3sats_in_view Tff7b72= Te6edf3pTb4b4b4.Te6edf3sats_in_viewTb4b4b4,
Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3pTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3time Tff7b72= Te6edf3posTimeTb4b4b4)
Tb4b4b4}
Te6edf3nodeTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3position Tff7b72= Te6edf3newPosTb4b4b4, Te6edf3lastHeard Tff7b72= Te6edf3newLastHeardTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffhandleReceivedTelemetryTb4b4b4(Te6edf3fromNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3telemetryTb4b4b4: Te6edf3TelemetryTb4b4b4) Tb4b4b4{
Te6edf3updateNodeTb4b4b4(Te6edf3fromNumTb4b4b4) Tb4b4b4{ Te6edf3node Tff7b72-Tff7b72>
Tff7b72var Te6edf3nextNode Tff7b72= Te6edf3node
Te6edf3telemetryTb4b4b4.Te6edf3device_metricsTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3nextNode Tff7b72= Te6edf3nextNodeTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3deviceMetrics Tff7b72= Tffa657itTb4b4b4) Tb4b4b4}
Te6edf3telemetryTb4b4b4.Te6edf3environment_metricsTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3nextNode Tff7b72= Te6edf3nextNodeTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3environmentMetrics Tff7b72= Tffa657itTb4b4b4) Tb4b4b4}
Te6edf3telemetryTb4b4b4.Te6edf3power_metricsTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3nextNode Tff7b72= Te6edf3nextNodeTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3powerMetrics Tff7b72= Tffa657itTb4b4b4) Tb4b4b4}
Te6edf3telemetryTb4b4b4.Te6edf3air_quality_metricsTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3nextNode Tff7b72= Te6edf3nextNodeTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3airQualityMetrics Tff7b72= Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3telemetryTime Tff7b72= Tff7b72if Tb4b4b4(Te6edf3telemetryTb4b4b4.Te6edf3time Tff7b72!Tff7b72= T79c0ff0Tb4b4b4) Te6edf3telemetryTb4b4b4.Te6edf3time Tff7b72else Te6edf3nodeTb4b4b4.Te6edf3lastHeard
Tff7b72val Te6edf3newLastHeard Tff7b72= Te6edf3clampTimestampToNowTb4b4b4(Te6edf3maxOfTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3lastHeardTb4b4b4, Te6edf3telemetryTimeTb4b4b4)Tb4b4b4)
Te6edf3nextNodeTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3lastHeard Tff7b72= Te6edf3newLastHeardTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffhandleReceivedPaxcounterTb4b4b4(Te6edf3fromNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3pTb4b4b4: Te6edf3PaxcountTb4b4b4) Tb4b4b4{
Te6edf3updateNodeTb4b4b4(Te6edf3fromNumTb4b4b4) Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3paxcounter Tff7b72= Te6edf3pTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffhandleReceivedNodeStatusTb4b4b4(Te6edf3fromNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3sTb4b4b4: Te6edf3StatusMessageTb4b4b4) Tb4b4b4{
Te6edf3updateNodeStatusTb4b4b4(Te6edf3fromNumTb4b4b4, Te6edf3sTb4b4b4.Te6edf3statusTb4b4b4)
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffupdateNodeStatusTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3statusTb4b4b4: Tffa657String?Tb4b4b4) Tb4b4b4{
Te6edf3updateNodeTb4b4b4(Te6edf3nodeNumTb4b4b4) Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3nodeStatus Tff7b72= Te6edf3statusTff7b72?.Te6edf3takeIf Tb4b4b4{ Te6edf3s Tff7b72-Tff7b72> Te6edf3sTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffinstallNodeInfoTb4b4b4(Te6edf3infoTb4b4b4: Te6edf3ProtoNodeInfoTb4b4b4) Tb4b4b4{
Te6edf3updateNodeTb4b4b4(Te6edf3infoTb4b4b4.Te6edf3numTb4b4b4) Tb4b4b4{ Te6edf3node Tff7b72-Tff7b72>
Tff7b72var Te6edf3next Tff7b72= Te6edf3node
Tff7b72val Te6edf3user Tff7b72= Te6edf3infoTb4b4b4.Te6edf3user
Tff7b72if Tb4b4b4(Te6edf3user Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3shouldPreserveExistingUserTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3userTb4b4b4, Te6edf3userTb4b4b4)Tb4b4b4) Tb4b4b4{
T8b949e// keep existing names
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72var Te6edf3newUser Tff7b72=
Te6edf3userTb4b4b4.Te6edf3let Tb4b4b4{ Tff7b72if Tb4b4b4(Tffa657itTb4b4b4.Te6edf3is_licensed Tff7b72=Tff7b72= Tff7b72trueTb4b4b4) Tffa657itTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3public_key Tff7b72= Te6edf3ByteStringTb4b4b4.Te6edf3EMPTYTb4b4b4) Tff7b72else Tffa657it Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3infoTb4b4b4.Te6edf3via_mqtt Tff7b72&Tff7b72& Tff7b72!Te6edf3newUserTb4b4b4.Te6edf3long_nameTb4b4b4.Te6edf3endsWithTb4b4b4(Ta5d6ff"Ta5d6ff (MQTT)Ta5d6ff"Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3newUser Tff7b72= Te6edf3newUserTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3long_name Tff7b72= Ta5d6ff"Tffd700${Te6edf3newUserTb4b4b4.Te6edf3long_nameTffd700}Ta5d6ff (MQTT)Ta5d6ff"Tb4b4b4)
Tb4b4b4}
Te6edf3next Tff7b72= Te6edf3nextTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3user Tff7b72= Te6edf3newUserTb4b4b4, Te6edf3publicKey Tff7b72= Te6edf3newUserTb4b4b4.Te6edf3public_keyTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72val Te6edf3position Tff7b72= Te6edf3infoTb4b4b4.Te6edf3position
Tff7b72if Tb4b4b4(Te6edf3position Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3clampedPos Tff7b72= Te6edf3positionTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3time Tff7b72= Te6edf3clampTimestampToNowTb4b4b4(Te6edf3positionTb4b4b4.Te6edf3timeTb4b4b4)Tb4b4b4)
Te6edf3next Tff7b72= Te6edf3nextTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3position Tff7b72= Te6edf3clampedPosTb4b4b4)
Tb4b4b4}
Te6edf3next Tff7b72=
Te6edf3nextTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3lastHeard Tff7b72= Te6edf3clampTimestampToNowTb4b4b4(Te6edf3infoTb4b4b4.Te6edf3last_heardTb4b4b4)Tb4b4b4,
Te6edf3deviceMetrics Tff7b72= Te6edf3infoTb4b4b4.Te6edf3device_metrics Tff7b72?: Te6edf3nextTb4b4b4.Te6edf3deviceMetricsTb4b4b4,
Te6edf3channel Tff7b72= Te6edf3infoTb4b4b4.Te6edf3channelTb4b4b4,
Te6edf3viaMqtt Tff7b72= Te6edf3infoTb4b4b4.Te6edf3via_mqttTb4b4b4,
Te6edf3hopsAway Tff7b72= Te6edf3infoTb4b4b4.Te6edf3hops_away Tff7b72?: Tff7b72-T79c0ff1Tb4b4b4,
Te6edf3isFavorite Tff7b72= Te6edf3infoTb4b4b4.Te6edf3is_favoriteTb4b4b4,
Te6edf3isIgnored Tff7b72= Te6edf3infoTb4b4b4.Te6edf3is_ignoredTb4b4b4,
Te6edf3isMuted Tff7b72= Te6edf3infoTb4b4b4.Te6edf3is_mutedTb4b4b4,
Tb4b4b4)
Te6edf3next
Tb4b4b4}
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8ffinsertMetadataTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3metadataTb4b4b4: Te6edf3DeviceMetadataTb4b4b4) Tb4b4b4{
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{ Te6edf3nodeRepositoryTb4b4b4.Te6edf3insertMetadataTb4b4b4(Te6edf3nodeNumTb4b4b4, Te6edf3metadataTb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffshouldPreserveExistingUserTb4b4b4(Te6edf3existingTb4b4b4: Te6edf3UserTb4b4b4, Te6edf3incomingTb4b4b4: Te6edf3UserTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3isDefaultName Tff7b72= Tb4b4b4(Te6edf3incomingTb4b4b4.Te6edf3long_nameTb4b4b4)Tb4b4b4.Te6edf3matchesTb4b4b4(Te6edf3RegexTb4b4b4(Ta5d6ff"Ta5d6ff^Meshtastic [0-9a-fA-F]{4}$Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3isDefaultHwModel Tff7b72= Te6edf3incomingTb4b4b4.Te6edf3hw_model Tff7b72=Tff7b72= Te6edf3HardwareModelTb4b4b4.Te6edf3UNSET
Tff7b72val Te6edf3hasExistingUser Tff7b72= Tb4b4b4(Te6edf3existingTb4b4b4.Te6edf3idTb4b4b4)Tb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Te6edf3existingTb4b4b4.Te6edf3hw_model Tff7b72!Tff7b72= Te6edf3HardwareModelTb4b4b4.Te6edf3UNSET
Tff7b72return Te6edf3hasExistingUser Tff7b72&Tff7b72& Te6edf3isDefaultName Tff7b72&Tff7b72& Te6edf3isDefaultHwModel
Tb4b4b4}
Tff7b72override Tff7b72fun Td2a8fftoNodeIDTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Tffa657String Tff7b72= Tff7b72if Tb4b4b4(Te6edf3nodeNum Tff7b72=Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3NODENUM_BROADCASTTb4b4b4) Tb4b4b4{
Te6edf3NodeAddressTb4b4b4.Te6edf3ID_BROADCAST
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3nodeIndexTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3byNumTff7b72[Te6edf3nodeNumTff7b72]Tff7b72?.Te6edf3userTff7b72?.Te6edf3id Tff7b72?: Te6edf3NodeAddressTb4b4b4.Te6edf3numToDefaultIdTb4b4b4(Te6edf3nodeNumTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.12s